﻿#pragma once


#include <string>
#include <mutex>
#include <memory>
#include <vector>
#include <functional>
#include "GameOffsets.h"
#include <Windows.h>
#include "skCrypter.h"
#include <array>
#include "msgpack.hpp"
#include "Event.h"
#define DEBUG_MODE 1

#ifdef DEBUG_MODE 
#define DEBUG_INFO_OUTPUTW(fmt, ...) \
    do { \
        const size_t bufferSize = 1024 * 4; \
        wchar_t buffer[bufferSize]; \
        _snwprintf_s(buffer, bufferSize, _TRUNCATE, fmt, __VA_ARGS__); \
        OutputDebugStringW(buffer); \
    } while (0)

#else  
#define DEBUG_INFO_OUTPUTW(fmt, ...)  
#endif

#ifdef DEBUG_MODE  
#define DEBUG_INFO_OUTPUT(fmt, ...) \
    do { \
        const size_t bufferSize = 1024 * 4; \
        char buffer[bufferSize]; \
        snprintf(buffer, bufferSize, fmt, __VA_ARGS__); \
        OutputDebugStringA(buffer); \
    } while (0)
#else  
#define DEBUG_INFO_OUTPUT(fmt, ...)  
#endif

class CUEString
{
public:
	wchar_t* str{};
	int len{};
};



struct SWidget
{
	float x;
	float y;
	float width;
	float height;
};

class TLPoint
{
public:
	TLPoint(float x_ , float y_ , float z_):x(x_) , y(y_) , z(z_) {};
	float x{};
	float y{};
	float z{};
};

//队伍信息
struct SPartyInfo
{
	size_t m_obj{};
	std::wstring m_name;
	std::string m_name_utf8;
	int m_hp{};
	int m_hpMax{};
	int m_mp{};
	int m_mpMax{};
	float m_x{};
	float m_y{};
	float m_z{};
	int m_level{};
	int m_dungeonID;//副本ID
	bool m_isCaptain{};//是否是队长
	MSGPACK_DEFINE(m_name_utf8, m_hp , m_hpMax , m_mp , m_mpMax , m_x , m_y  , m_z , m_level , m_dungeonID  , m_isCaptain);
};
using SPartyInfoSharedPtr = std::shared_ptr<SPartyInfo>;

//效果链表，游戏 里的buff列表
struct SEffect
{
	std::string name;
	size_t m_obj;

	// 为 SEffect 定义 MSGPACK_DEFINE  
	MSGPACK_DEFINE(name, m_obj);
};

using SEffectSharedPtr = std::shared_ptr<SEffect>;

//攻击技能信息
typedef struct SAttackInfo_s
{
	//double m_castTime{};//施法时间
	//double m_chargingTime{};//蓄力时间
	UINT32 m_skillTargetID{};//目标id
	std::string m_skillName;//技能名
	double m_skillChargeRemainingTime{};//技能蓄力剩余时间
	//float m_skillAttackSpeed{}; //技能攻击速度
}SAttackInfo;

//演员类
class CActor
{
public:
	UINT64 m_obj{};
	bool m_LocalPlayers{};
	float m_x{};
	float m_y{};
	float m_z{};
	float m_vx{};
	float m_vy{};
	float m_vz{};
	bool m_isAlive{};	//是否活着
	bool m_isAttackable{};	//是否可攻击..
	bool m_isLocal{};
	int m_selectID{};
	std::wstring m_name;
	std::string m_utf8name;
	std::wstring m_areaName;
	std::string m_utf8AreaName;
	float m_hp{};
	float m_hpMax{};
	float m_mp{};
	float m_mpMax{};
	int m_id{};
	float m_distance{};//与人物距离
	int m_castID{};
	UINT32 m_targetID;
	bool m_isAnimation{};
	bool m_isMove{};
	int m_weaponIndex{};
	UINT64 m_worldMessageCharacterId{};
	UINT32 m_level{};
	float m_stamina{};//体能，例如格挡需要体能
	int m_statPoints{};//属性点
	int m_strength{};//斗志
	int m_dexterity{};//中气
	int m_wisdom{};//智慧
	int m_perception{};//洞察
	bool m_isDaytime{};//是否是白天
	bool m_isDungeon{};//是否在地牢
	bool m_isPlayer{};//是否是玩家
	UINT64 m_gold{};//金币
	SAttackInfo m_attackInfo;//攻击技能信息
	std::vector<SEffectSharedPtr> m_Effects;
	int m_abyssPoint{};//深渊点数
	int m_PartyDungeonPoint{};//副本点数
	int m_ContractPoint{};//委托卷数量


	//取攻击目标信息
	//void GetAttackInfo(SAttackInfo&);

	//取虚拟坐标
	//bool GetObjPoint(TLPoint* v);
	MSGPACK_DEFINE(m_obj, m_LocalPlayers, m_x, m_y, m_z, m_vx, m_vy, m_vz, m_isAlive, m_isAttackable, m_isLocal, m_selectID, m_utf8name, m_utf8AreaName, m_hp, m_hpMax, m_mp, m_mpMax, m_id, m_distance, m_castID, m_isAnimation, m_isMove, m_weaponIndex, m_worldMessageCharacterId, m_level, m_targetID, m_stamina, m_statPoints, m_strength, m_dexterity, m_wisdom, m_perception, m_isDaytime, m_gold, m_isPlayer, m_attackInfo.m_skillTargetID, m_attackInfo.m_skillName, m_attackInfo.m_skillChargeRemainingTime, m_abyssPoint , m_PartyDungeonPoint  , m_ContractPoint, m_isDungeon ,  m_Effects);
};
//属性点 0x5b0
//斗志		+0x8
//中气		+0xc
//智慧		0x10
//洞察		0x14
using CActorSharedPtr = std::shared_ptr<CActor>;

class STeleportPoint
{
public:
	STeleportPoint()
	{

	}
	STeleportPoint(const char* a1, UINT64 a2, bool a3) : name(a1), id(a2), isOpen(a3)
	{

	}

	std::string name;
	UINT64 id{};
	bool isOpen{};

	MSGPACK_DEFINE(name, id, isOpen);

};
//日程表
struct SSchedule
{
	std::wstring name{};//日程名
	std::wstring description{};//日程描述
	std::string name_utf8;
	std::string description_utf8;
	char type{};
	MSGPACK_DEFINE(name_utf8, description_utf8, type);
};

using SScheduleSharedPtr = std::shared_ptr<SSchedule>;
using STeleportPointSharedPtr = std::shared_ptr<STeleportPoint>;

class CQuickSlot
{
public:
	std::wstring m_Name;
	std::string m_name_utf8;
	bool m_cooling;//冷却中
	int m_index;//快捷栏序号
	bool m_bright;//快捷栏是否是明亮的状态
	float m_coolingTime; //冷却时间
	float m_resources;//消耗资源
	float m_distance;//距离

public:
	bool operator==(const CQuickSlot& other) const {
		return  m_cooling == other.m_cooling && m_bright == other.m_bright && m_Name == other.m_Name;
	}

	MSGPACK_DEFINE(m_name_utf8 , m_cooling, m_index , m_bright , m_coolingTime, m_resources , m_distance);
};

class CSkill
{
public:
	int m_id1{};
	int m_id2{};
	UINT64 m_level{};
	UINT64 m_obj{};
	float m_Cooldown{};//冷却时间
	float m_ResourceCost{};//资源成本
	float m_Distance{};//距离
	bool m_IsCooldown{};//是否正在冷却
	std::wstring m_name;
	std::string m_name_utf8;

	MSGPACK_DEFINE(m_id1 , m_id2 , m_level , m_ResourceCost , m_Distance , m_IsCooldown , m_name_utf8);
};

using CQuickSlotSharedPtr = std::shared_ptr<CQuickSlot>;
using CSkillSharedPtr = std::shared_ptr<CSkill>;



struct SExecution
{
	int Count;	//当前目标数量
	int MaxCount;//最大目标数量
	UINT64 Id;
	bool IsComplete;//是否完成
	std::wstring Describe;//任务描述
	std::string Describeutf8;
	MSGPACK_DEFINE(Count , MaxCount , Id , IsComplete , Describeutf8)
};
using SExecutionSharedPtr = std::shared_ptr<SExecution>;

class CTask
{
public:
	std::wstring m_Name;//任务名
	std::string m_nameutf8;
	__int64 m_Id{};
	UINT64 m_Obj{};
	std::vector<SExecutionSharedPtr> m_ExecutionList;//执行列表
	MSGPACK_DEFINE(m_nameutf8 , m_Id , m_ExecutionList)
};

using CTaskSharedPtr = std::shared_ptr<CTask>;


class CItem
{
public:
	UINT64 m_obj{};
	__int64 m_id{};
	unsigned char m_category{}; //类别，例如 头盔 长弓 双手剑 ...
	int m_count{}; //物品数量
	int m_id2{};
	std::wstring m_name;
	std::string m_name_utf8;
	unsigned char m_level{}; //等级
	unsigned char m_colour{}; //颜色品质 ， 4：稀有 3：高档 2：普通
	bool m_equipment{};//是否装备

	MSGPACK_DEFINE(m_id , m_id2 , m_category , m_count , m_name_utf8 , m_level , m_colour , m_equipment);
};
using CItemSharedPtr = std::shared_ptr<CItem>;



extern UINT64 g_TLMyPc;
extern UINT64 g_TLMap;
extern UINT64 g_TLCodex;
extern UINT64 g_TLTableMaster;
extern UINT64 g_TLSkillQuickSlotObjectGroupActive;
extern UINT64 g_TLInventory;
extern UINT64 g_SpringArmComp;
extern UINT64 g_TLTargetHelper;
extern UINT64 g_TLServerManager;
extern UINT64 g_TLSkillFormula;
extern UINT64 g_TLTerritoryFog;
extern UINT64 g_TLSkillSet;
extern UINT64 g_TTLCalendar;
extern UINT64 g_TLTimeTable;
extern UINT64 g_TLEquip;
extern UINT64 g_TLGameModeController;
extern UINT64 g_TLParty;
extern UINT64 g_TLMapIcon;

namespace NetworkProtocol
{
	namespace AFAPI
	{
		namespace ClientToServer
		{
			const int ShutdownGameRequest = 10000;
			const int ReadVirtualMemoryRequest = 10001;
			const int WriteVirtualMemoryRequest = 10002;
			const int AllocateVirtualMemoryRequest = 10003;
			const int FreeVirtualMemoryRequest = 10004;
			const int ProtectVirtualMemoryRequest = 10005;
			const int FindModuleByNameRequest = 10006;
			const int GetModuleByNameRequest = 10007;
			const int GetAllModulesRequest = 10008;
			const int ExecuteShellCodeRequest = 10009;
			const int GetProcAddressSafeRequest = 10010;
			const int SendMouseInputRequest = 10011;
			const int GetCursorPositionRequest = 10012;
			const int SetCursorPositionRequest = 10013;
			const int SendKeyboardInputRequest = 10014;
			const int ScriptAPIFacingCoordinatesRequest = 10015;	//?????
			const int ScriptAPISelectObjRequest = 10016;			//??????
			const int ScriptAPIAreaTeleportRequest = 10017;			//??????
			const int ScriptAPISpecifyTasksRequest = 10018;			//????????
			const int ScriptAPIUseEquipmentRequest = 10019;			//???????
			const int ScriptAPIFindSWidgetRequest = 10020;			//????UI
			const int ScriptAPIUpdateTeleportPointRequest = 10021;			//?????????.
			const int ScriptAPIUpdateSkillsRequest = 10022;			//????????.
			const int ScriptAPIItemUsageRequest = 10023;			//????????
			const int ScriptAPIUseConsumableWithQuantityRequest = 10024;			//????????
			const int ScriptAPIOngoingScheduleRequest = 10025;			//???????????????
			const int ScriptAPIInteractiveRequest = 10026;			//????
			const int ScriptAPIMovToActorRequest = 10027;			//?????????
			const int ScriptAPISetCharacterNameRequest = 10028;			//新手剧情设置名字
			const int ScriptAPIGetInventoryRequest = 10029;			//获取背包数据
			const int ScriptAPIMoveToRequest = 10030;			//移动至坐标
			const int ScriptAPIToggleKeepMoveForwardRequest = 10031;			//自动前进
			const int ScriptAPIMouseClickRequest = 10032;			//鼠标点击
			const int ScriptAPIExecuteKeyPressRequest = 10033;			//执行按键
			const int ScriptAPIInviteToTeamRequest = 10034;			//组队邀请
			const int ScriptAPITeleport_sbwwRequest = 10035;			//传送_士兵娃娃之家
			const int ScriptAPIUpdatePartyInfoRequest = 10036;			//获取队伍信息
			
			


			
			
			const int GetHwidStringRequest = 10099;
			const int GetAFTLVersionRequest = 10999;//???AFModule??汾??,?????????
		};

		namespace ServerToClient
		{
			const int Init = 0;
			const int ReadVirtualMemoryResponse = 1;
			const int WriteVirtualMemoryResponse = 2;
			const int AllocateVirtualMemoryResponse = 3;
			const int FreeVirtualMemoryResponse = 4;
			const int ProtectVirtualMemoryResponse = 5;
			const int FindModuleByNameResponse = 6;
			const int GetModuleByNameResponse = 7;
			const int GetAllModulesResponse = 8;
			const int ExecuteShellCodeResponse = 9;
			const int GetProcAddressSafeResponse = 10;
			const int SendMouseInputResponse = 11;
			const int GetCursorPositionResponse = 12;
			const int SetCursorPositionResponse = 13;
			const int SendKeyboardInputResponse = 14;
			const int ScriptAPIFacingCoordinatesResponse = 15;
			const int ScriptAPISelectObjResponse = 16;//??????
			const int ScriptAPIAreaTeleportResponse = 17;
			const int ScriptAPISpecifyTasksResponse = 18;//????????
			const int ScriptAPIUseEquipmentResponse = 19;//????????
			const int ScriptAPIFindSWidgetResponse = 19;//?UI
			const int ScriptAPIFinAPIUpdateTeleportPointResponse = 20;//?????????
			const int ScriptAPIFinAPIUpdateSkillsResponse = 21;//????????
			const int ScriptAPIItemUsageResponse = 22;			//????????

			const int GetHwidStringResponse = 99;
			const int GetAFTLVersionResponse = 999;//???AFModule??汾??,?????????

			const int SendRangeObject = 100;
			const int SendQuickSlot = 101;
			const int SendInventory = 102;
			const int SendTaskAdventureExploration = 103;
			const int SendTaskDelegation = 104;
			const int SendEffects = 105;//????Ч??????

			const int LogEvent = 200;
			const int RequestFailure = 9999;

		};
	};
};

bool IsReadPtr(UINT64 add);

template<typename T>
inline T GameCore_read(size_t addr)
{
	if (IsReadPtr(addr))
	{
		return *((T*)addr);
	}
	return 0;
}

template<typename T, size_t n>
inline T GameCore_read(size_t addr, const std::array<size_t, n>& offsets)
{
	UINT64 tmpAddr = addr;
	T ret = 0;
	for (size_t i = 0; i < offsets.size(); i++)
	{
		if (i + 1 == offsets.size())
		{
			ret = GameCore_read<T>(tmpAddr + offsets[i]);
		}
		else
		{
			tmpAddr = GameCore_read<size_t>(tmpAddr + offsets[i]);
			if (!tmpAddr)
			{
				return 0;
			}
		}

	}
	return ret;
}

inline size_t GameCore_read(size_t addr, void* output, size_t Len)
{
	size_t dwReadBytes{};
	if (memcpy_s(output, Len, (char*)addr, Len) == 0)
	{
		return Len;
	}
	return 0;
}

template<typename T>
inline void GameCore_write(UINT64 addr, T val)
{
	*((T*)addr) = val;
}

//
size_t GameCore_GetGameBaseAddress();


void UtilUnicodeToUTF8(const std::wstring& unicodeStr, std::string& outUtf8Str);

void UtilUTF8ToUnicode(const std::string& utf8Str, std::wstring& outWstr);



SIZE_T GameCore_GetPeSize(HMODULE hModule);



//取GNAME
void GameCore_GetNameUE(unsigned int id, std::string& out);

bool GameCore_GetObjPoint(size_t obj , TLPoint* v);

//通过完整路径名取对象
void GameCore_UENameToObj(const std::string& name, bool isPrint, std::vector<UINT64>& out);

//取对象文本
bool GameCore_UEGetText(UINT64 nameObj, std::wstring& output);

//虚拟坐标转真实坐标
void GameCore_PointVToR(TLPoint* v);

//真实坐标转虚拟坐标
void GameCore_PointRToV(TLPoint* r);

//技能是否冷却中
//如果是技能 AttributeObj : [skillObj+0xf0] 或者 [结构体+0x70]
//如果是物品 AttributeObj : [[itemObj+0x110]+0x138] 或则 [结构+0x38]+0x138
bool GameCore_IsSkillCooldown(UINT64 AttributeObjPtr);

bool GameCore_IsObjectAttackable(UINT64 obj);

bool GameCore_IsObjectAlive(UINT64 obj);

//取item名字对象，[返回值+0x30]就是名字对象
//FieldObj 字段对象
UINT64 GameCore_ItemToNameObj(UINT64 FieldObj);

//rcx = [/Engine/Transient.TLGameEngine.BP_TLGameInstance_C.TLTableMaster + 0x598] + 0x28-0x8
void GameCore_TaskGetIDToText(UINT64 textID, std::wstring& text);

//取出描述文本，并遍历参数，格式化到文本里
void GameCore_DescriptionTextFormatting(UINT64 arrayNode, std::wstring& DescribeText);

//取出委托任务描述文本，并遍历参数，格式化到文本里
//jinduObj 进度对象
void GameCore_DelegateDescriptionTextFormatting(UINT64 jinduObj, std::wstring& DescribeText);

//任务是否完成
//ExecutionID:主任务的进度id
bool GameCore_TaskIsComplete(UINT64 ExecutionID);

//传入委托任务ID，返回一个结构体，[[struct+0xa8]+0x8] 是任务名text对象
//DelegateTaskGetStruct 就是 fs_DelegateTaskGetStruct , 为了效率我自己用读内存实现了此函数
UINT64 GameCore_DelegateTaskGetStruct(UINT64 taskID);

//发送protobuf二进制数据包
int GameCore_SendPacket(short id, void* buf, __int64 len);

//数据报加密
UINT64 GameCore_EncryptPacket(UINT64 a1, SIZE_T bufLen, const void* inputBuf, void* outputBuf);


//取技能的属性对象，里面有 消耗资源 ， 距离 等属性
//AttributeID =  read<UINT32>(skill->m_obj, { skillAttributeOffset , 0x10})，  或者技能栏数组 结构体+0x70
UINT64 GameCore_SkillGetAttribute(UINT32 AttributeID);

//获取子控件数量
UINT32 GameCore_SWidgetGetSubObjSize(UINT64 obj);

//获取子控件对象
void GameCore_SWidgetGetSubObj(UINT64 obj, UINT64* output, UINT32 i);

class CEnumSWidgetsContext
{
public:
	std::function<bool(UINT64 obj, const std::wstring& text)> callback;//回调函数
	std::vector<UINT64> subctx;//接下来要遍历的控件对象（用于模拟递归行为）
	std::vector<UINT64> freectx;//最后要释放的引用计数
	bool stopped{};//是否停止遍历
};

//遍历控件对象(及其所有子控件) 参数：主功能，回调函数
void GameCore_EnumSWidgets(UINT64 widget, const std::function<bool(UINT64 obj, const std::wstring& text)>& callback);

//取UI根对象
UINT64 GameCore_SWidgetGetRoot();

//取UI窗口矩形
void GameCore_SWidgetGetRect(UINT64 widget, SWidget& rect);

//
UINT64 GetSubObjSize_SInvalidationPanel(UINT64 obj);

//
void GetSubObj_SInvalidationPanel(DWORD64 obj, UINT64* output, UINT32 i);

//递归？
void GameCore_SInvalidationPanelRecursion(DWORD64 widget, CEnumSWidgetsContext* context);

//传送点是否开通CALL
bool IsTeleportPointOpen(DWORD64 id);

//根据技能id1取一个对象
UINT64 SkillID1ToAttribute(UINT32 id);

//根据 SkillID1ToAttribute返回的对象取技能等级
UINT64 GetSkillLevel(UINT64 AttributeObj);

//取游戏货币，有很多种类
UINT64 GetCurrency(UINT8 type);

//获得日程信息CALL
UINT64 GetScheduleInfo(UINT64 id);

//交互CALL
UINT64 GameCore_Interactive(int actor_id);

//移动到对象
bool GameCore_MovToActor(int actor_id, int type = 5);

//
void GameCore_GetAttackInfo(size_t m_obj, const std::map<int, float>& m_skillAttackSpeed, SAttackInfo& attackInfo);

//
bool GameCore_IsPlayer(UINT64 obj);

//面向
void GameCore_FacingCoordinates(CActorSharedPtr LocalPlayer , const TLPoint& p);

void ScriptAPI_UseEquipment(UINT64 id, UINT32 index);

bool ScriptAPI_FindSWidget(const std::string& text, OUT SWidget& rect);

//使用消耗物品
void ScriptAPI_UseConsumable(UINT64 itemID, int itemID2, int destID, float destX, float destY, float destZ);

void ScriptAPI_useConsumableWithQuantity(UINT64 itemID, int sum);

//交互
//type:0为对话 1为钩锁
void ScriptAPI_Interactive(UINT64 id, UINT64 type);

//新手剧情设置名字
void ScriptAPI_SetCharacterName(std::string name);

float GameCore_GetObjectDistance(const CActor* actor1, const CActor* actor2);

//移动至坐标
void GameCore_MoveTo(float vx , float vy , float vz);

//自动前进
void GameCore_ToggleKeepMoveForward();

//鼠标点击
void GameCore_MouseClick(int hwnd , int x , int y , int mode);

//
void GameCore_ExecuteKeyPress(int hwnd, UINT keyCode, int mode);

//根据id取一个对象，例如 取深渊点数对象
UINT64 GameCore_IDToObj(UINT64 id);

//队伍信息里，根据一个ID取一个结构体，结构体+0x28是真实坐标
size_t GameCore_PartyGetStructById(size_t ID);

//是否在地牢中
bool GameCore_IsDungeon();